home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / AVIReadHandler.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-25  |  55.1 KB  |  2,262 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <crtdbg.h>
  19.  
  20. #include <windows.h>
  21.  
  22. #include "AVIReadHandler.h"
  23. #include "FastReadStream.h"
  24. #include "ProgressDialog.h"
  25. #include "AVIIndex.h"
  26. #include "Error.h"
  27. #include "List.h"
  28. #include "Fixes.h"
  29. #include "File64.h"
  30. #include "Avisynth.h"
  31.  
  32. //#define STREAMING_DEBUG
  33.  
  34. // HACK!!!!
  35.  
  36. CRITICAL_SECTION g_diskcs;
  37. bool g_disklockinited=false;
  38.  
  39.  
  40. ///////////////////////////////////////////
  41.  
  42. typedef __int64 QUADWORD;
  43.  
  44. // The following comes from the OpenDML 1.0 spec for extended AVI files
  45.  
  46. // bIndexType codes
  47. //
  48. #define AVI_INDEX_OF_INDEXES 0x00    // when each entry in aIndex
  49.                                     // array points to an index chunk
  50.  
  51. #define AVI_INDEX_OF_CHUNKS 0x01    // when each entry in aIndex
  52.                                     // array points to a chunk in the file
  53.  
  54. #define AVI_INDEX_IS_DATA    0x80    // when each entry is aIndex is
  55.                                     // really the data
  56.  
  57. // bIndexSubtype codes for INDEX_OF_CHUNKS
  58.  
  59. #define AVI_INDEX_2FIELD    0x01    // when fields within frames
  60.                                     // are also indexed
  61.     struct _avisuperindex_entry {
  62.         QUADWORD qwOffset;        // absolute file offset, offset 0 is
  63.                                 // unused entry??
  64.         DWORD dwSize;            // size of index chunk at this offset
  65.         DWORD dwDuration;        // time span in stream ticks
  66.     };
  67.     struct _avistdindex_entry {
  68.         DWORD dwOffset;            // qwBaseOffset + this is absolute file offset
  69.         DWORD dwSize;            // bit 31 is set if this is NOT a keyframe
  70.     };
  71.     struct _avifieldindex_entry {
  72.         DWORD    dwOffset;
  73.         DWORD    dwSize;
  74.         DWORD    dwOffsetField2;
  75.     };
  76.  
  77. #pragma pack(push)
  78. #pragma pack(2)
  79.  
  80. typedef struct _avisuperindex_chunk {
  81.     FOURCC fcc;                    // Æix##Æ
  82.     DWORD cb;                    // size of this structure
  83.     WORD wLongsPerEntry;        // must be 4 (size of each entry in aIndex array)
  84.     BYTE bIndexSubType;            // must be 0 or AVI_INDEX_2FIELD
  85.     BYTE bIndexType;            // must be AVI_INDEX_OF_INDEXES
  86.     DWORD nEntriesInUse;        // number of entries in aIndex array that
  87.                                 // are used
  88.     DWORD dwChunkId;            // Æ##dcÆ or Æ##dbÆ or Æ##wbÆ, etc
  89.     DWORD dwReserved[3];        // must be 0
  90.     struct _avisuperindex_entry aIndex[];
  91. } AVISUPERINDEX, * PAVISUPERINDEX;
  92.  
  93. typedef struct _avistdindex_chunk {
  94.     FOURCC fcc;                    // Æix##Æ
  95.     DWORD cb;
  96.     WORD wLongsPerEntry;        // must be sizeof(aIndex[0])/sizeof(DWORD)
  97.     BYTE bIndexSubType;            // must be 0
  98.     BYTE bIndexType;            // must be AVI_INDEX_OF_CHUNKS
  99.     DWORD nEntriesInUse;        //
  100.     DWORD dwChunkId;            // Æ##dcÆ or Æ##dbÆ or Æ##wbÆ etc..
  101.     QUADWORD qwBaseOffset;        // all dwOffsets in aIndex array are
  102.                                 // relative to this
  103.     DWORD dwReserved3;            // must be 0
  104.     struct _avistdindex_entry aIndex[];
  105. } AVISTDINDEX, * PAVISTDINDEX;
  106.  
  107. typedef struct _avifieldindex_chunk {
  108.     FOURCC        fcc;
  109.     DWORD        cb;
  110.     WORD        wLongsPerEntry;
  111.     BYTE        bIndexSubType;
  112.     BYTE        bIndexType;
  113.     DWORD        nEntriesInUse;
  114.     DWORD        dwChunkId;
  115.     QUADWORD    qwBaseOffset;
  116.     DWORD        dwReserved3;
  117.     struct    _avifieldindex_entry aIndex[];
  118. } AVIFIELDINDEX, * PAVIFIELDINDEX;
  119.  
  120. #pragma pack(pop)
  121.  
  122. ///////////////////////////////////////////////////////////////////////////
  123.  
  124. IAVIReadStream::~IAVIReadStream() {
  125. }
  126.  
  127. ///////////////////////////////////////////////////////////////////////////
  128.  
  129. class AVIStreamNode;
  130. class AVIReadHandler;
  131.  
  132. class AVIReadCache {
  133. public:
  134.     long cache_hit_bytes, cache_miss_bytes;
  135.     int reads;
  136.  
  137.     AVIReadCache(int nlines, int nstream, AVIReadHandler *root, AVIStreamNode *psnData);
  138.     ~AVIReadCache();
  139.  
  140.     void ResetStatistics();
  141.     bool WriteBegin(__int64 pos, long len);
  142.     void Write(void *buffer, long len);
  143.     void WriteEnd();
  144.     long Read(void *dest, __int64 chunk_pos, __int64 pos, long len);
  145.  
  146. private:
  147.     AVIStreamNode *psnData;
  148.     __int64 (*buffer)[2];
  149.     int lines_max, lines;
  150.     long read_tail, write_tail, write_hdr;
  151.     int write_offset;
  152.     int stream;
  153.     AVIReadHandler *source;
  154. };
  155.  
  156. class AVIStreamNode : public ListNode2<AVIStreamNode> {
  157. public:
  158.     AVIStreamHeader_fixed    hdr;
  159.     void                    *pFormat;
  160.     long                    lFormatLen;
  161.     AVIIndex                index;
  162.     __int64                    bytes;
  163.     bool                    keyframe_only;
  164.     int                        handler_count;
  165.     class AVIReadCache        *cache;
  166.     int                        streaming_count;
  167.     __int64                    stream_push_pos;
  168.     __int64                    stream_bytes;
  169.     int                        stream_pushes;
  170.     long                    length;
  171.     long                    frames;
  172.     List2<class AVIReadStream>    listHandlers;
  173.  
  174.     AVIStreamNode();
  175.     ~AVIStreamNode();
  176. };
  177.  
  178. AVIStreamNode::AVIStreamNode() {
  179.     pFormat = NULL;
  180.     bytes = 0;
  181.     handler_count = 0;
  182.     streaming_count = 0;
  183.     
  184.     stream_bytes = 0;
  185.     stream_pushes = 0;
  186.     cache = NULL;
  187. }
  188.  
  189. AVIStreamNode::~AVIStreamNode() {
  190.     delete pFormat;
  191.     delete cache;
  192. }
  193.  
  194. ///////////////////////////////////////////////////////////////////////////
  195.  
  196. class AVIFileDesc : public ListNode2<AVIFileDesc> {
  197. public:
  198.     HANDLE        hFile;
  199.     HANDLE        hFileUnbuffered;
  200.     __int64        i64Size;
  201. };
  202.  
  203. class AVIStreamNode;
  204.  
  205. class AVIReadHandler : public IAVIReadHandler, private File64 {
  206. public:
  207.     bool        fDisableFastIO;
  208.  
  209.     AVIReadHandler(const char *);
  210.     AVIReadHandler(PAVIFILE);
  211.     ~AVIReadHandler();
  212.  
  213.     void AddRef();
  214.     void Release();
  215.     IAVIReadStream *GetStream(DWORD fccType, LONG lParam);
  216.     void EnableFastIO(bool);
  217.     bool isOptimizedForRealtime();
  218.     bool isStreaming();
  219.     bool isIndexFabricated();
  220.     bool AppendFile(const char *pszFile);
  221.     bool getSegmentHint(const char **ppszPath);
  222.  
  223.     void EnableStreaming(int stream);
  224.     void DisableStreaming(int stream);
  225.     void AdjustRealTime(bool fRealTime);
  226.     bool Stream(AVIStreamNode *, _int64 pos);
  227.     __int64 getStreamPtr();
  228.     void FixCacheProblems(class AVIReadStream *);
  229.     long ReadData(int stream, void *buffer, __int64 position, long len);
  230.  
  231. private:
  232. //    enum { STREAM_SIZE = 65536 };
  233.     enum { STREAM_SIZE = 1048576 };
  234.     enum { STREAM_RT_SIZE = 65536 };
  235.     enum { STREAM_BLOCK_SIZE = 4096 };
  236.  
  237.     IAvisynthClipInfo *pAvisynthClipInfo;
  238.     PAVIFILE paf;
  239.     int ref_count;
  240.     __int64        i64StreamPosition;
  241.     int            streams;
  242.     char        *streamBuffer;
  243.     int            sbPosition;
  244.     int            sbSize;
  245.     long        fStreamsActive;
  246.     int            nRealTime;
  247.     int            nActiveStreamers;
  248.     bool        fFakeIndex;
  249.     __int64        i64Size;
  250.     int            nFiles, nCurrentFile;
  251.     char *        pSegmentHint;
  252.  
  253.     List2<AVIStreamNode>        listStreams;
  254.     List2<AVIFileDesc>            listFiles;
  255.  
  256.     void        _construct(const char *pszFile);
  257.     void        _parseFile(List2<AVIStreamNode>& streams);
  258.     bool        _parseStreamHeader(List2<AVIStreamNode>& streams, DWORD dwLengthLeft);
  259.     bool        _parseIndexBlock(List2<AVIStreamNode>& streams, int count, __int64);
  260.     void        _parseExtendedIndexBlock(List2<AVIStreamNode>& streams, AVIStreamNode *pasn, __int64 fpos, DWORD dwLength);
  261.     void        _destruct();
  262.  
  263.     char *        _StreamRead(long& bytes);
  264.     void        _SelectFile(int file);
  265.  
  266. };
  267.  
  268. IAVIReadHandler *CreateAVIReadHandler(PAVIFILE paf) {
  269.     return new AVIReadHandler(paf);
  270. }
  271.  
  272. IAVIReadHandler *CreateAVIReadHandler(const char *pszFile) {
  273.     return new AVIReadHandler(pszFile);
  274. }
  275.  
  276. ///////////////////////////////////////////////////////////////////////////
  277.  
  278. AVIReadCache::AVIReadCache(int nlines, int nstream, AVIReadHandler *root, AVIStreamNode *psnData) {
  279.     buffer = new __int64[nlines][2];
  280.     if (!buffer) throw MyMemoryError();
  281.  
  282.     this->psnData    = psnData;
  283.     lines        = 0;
  284.     lines_max    = nlines;
  285.     read_tail    = 0;
  286.     write_tail    = 0;
  287.     stream        = nstream;
  288.     source        = root;
  289.     ResetStatistics();
  290. }
  291.  
  292. AVIReadCache::~AVIReadCache() {
  293.     delete[] buffer;
  294. }
  295.  
  296. void AVIReadCache::ResetStatistics() {
  297.     reads        = 0;
  298.     cache_hit_bytes    = cache_miss_bytes = 0;
  299. }
  300.  
  301. bool AVIReadCache::WriteBegin(__int64 pos, long len) {
  302.     int needed;
  303.  
  304.     // delete lines as necessary to make room
  305.  
  306.     needed = 1 + (len+15)/16;
  307.  
  308.     if (needed > lines_max)
  309.         return false;
  310.  
  311.     while(lines+needed > lines_max) {
  312.         int siz = (int)((buffer[read_tail][1]+15)/16 + 1);
  313.         read_tail += siz;
  314.         lines -= siz;
  315.         if (read_tail >= lines_max)
  316.             read_tail -= lines_max;
  317.     }
  318.  
  319.     // write in header
  320.  
  321. //    _RPT1(0,"\tbeginning write at line %ld\n", write_tail);
  322.  
  323.     write_hdr = write_tail;
  324.     write_offset = 0;
  325.  
  326.     buffer[write_tail][0] = pos;
  327.     buffer[write_tail][1] = 0;
  328.  
  329.     if (++write_tail >= lines_max)
  330.         write_tail = 0;
  331.  
  332.     return true;
  333. }
  334.  
  335. void AVIReadCache::Write(void *src, long len) {
  336.     long dest;
  337.  
  338.     // copy in data
  339.  
  340.     buffer[write_hdr][1] += len;
  341.  
  342.     dest = write_tail + (len + write_offset + 15)/16;
  343.  
  344.     if (dest > lines_max) {
  345.         int tc = (lines_max - write_tail)*16 - write_offset;
  346.  
  347.         memcpy((char *)&buffer[write_tail][0] + write_offset, src, tc);
  348.         memcpy(&buffer[0][0], (char *)src + tc, len - tc);
  349.  
  350.         write_tail = (len-tc)/16;
  351.         write_offset = (len-tc)&15;
  352.  
  353.     } else {
  354.         memcpy((char *)&buffer[write_tail][0] + write_offset, src, len);
  355.         write_tail += (len+write_offset)/16;
  356.         if (write_tail >= lines_max)
  357.             write_tail = 0;
  358.  
  359.         write_offset = (len+write_offset) & 15;
  360.     }
  361. }
  362.  
  363. void AVIReadCache::WriteEnd() {
  364.     long cnt = (long)(1 + (buffer[write_hdr][1]+15)/16);
  365.     lines += cnt;
  366.     write_tail = write_hdr + cnt;
  367.  
  368.     if (write_tail >= lines_max)
  369.         write_tail -= lines_max;
  370.  
  371. //    _RPT3(0,"\twrite complete -- header at line %d, size %ld, next line %ld\n", write_hdr, (long)buffer[write_hdr][1], write_tail);
  372. }
  373.  
  374. #pragma function(memcpy)
  375.  
  376. long AVIReadCache::Read(void *dest, __int64 chunk_pos, __int64 pos, long len) {
  377.     long ptr;
  378.     __int64 offset;
  379.  
  380. //    _RPT3(0,"Read request: chunk %16I64, pos %16I64d, %ld bytes\n", chunk_pos, pos, len);
  381.  
  382.     ++reads;
  383.  
  384.     do {
  385.         // scan buffer looking for a range that contains data
  386.  
  387.         ptr = read_tail;
  388.         while(ptr != write_tail) {
  389.             offset = pos - buffer[ptr][0];
  390.  
  391. //        _RPT4(0,"line %8d: pos %16I64d, len %ld bytes (%ld lines)\n", ptr, buffer[ptr][0], (long)buffer[ptr][1], (long)(buffer[ptr][1]+15)/16);
  392.  
  393.             if (offset>=0 && offset < buffer[ptr][1]) {
  394.                 long end;
  395.  
  396.                 // cache hit
  397.  
  398. //                _RPT1(0, "cache hit (offset %I64d)\n", chunk_pos);
  399.  
  400.                 cache_hit_bytes += len;
  401.  
  402.                 while (cache_hit_bytes > 16777216) {
  403.                     cache_miss_bytes >>= 1;
  404.                     cache_hit_bytes >>= 1;
  405.                 }
  406.  
  407.                 if (len > (long)(buffer[ptr][1]*16 - offset))
  408.                     len = (long)(buffer[ptr][1]*16 - offset);
  409.  
  410.                 ptr += 1+((long)offset>>4);
  411.                 if (ptr >= lines_max)
  412.                     ptr -= lines_max;
  413.  
  414.                 end = ptr + ((len+((long)offset&15)+15)>>4);
  415.  
  416.                 if (end > lines_max) {
  417.                     long tc = (lines_max - ptr)*16 - ((long)offset&15);
  418.                     memcpy(dest, (char *)&buffer[ptr][0] + ((long)offset&15), tc);
  419.                     memcpy((char *)dest + tc, (char *)&buffer[0][0], len-tc);
  420.                 } else {
  421.                     memcpy(dest, (char *)&buffer[ptr][0] + ((long)offset&15), len);
  422.                 }
  423.  
  424.                 return len;
  425.             }
  426.  
  427. //        _RPT4(0,"[x] line %8d: pos %16I64d, len %ld bytes (%ld lines)\n", ptr, buffer[ptr][0], (long)buffer[ptr][1], (long)(buffer[ptr][1]+15)/16);
  428.             ptr += (long)(1+(buffer[ptr][1] + 15)/16);
  429.  
  430.             if (ptr >= lines_max)
  431.                 ptr -= lines_max;
  432.         }
  433.  
  434.         if (source->getStreamPtr() > chunk_pos)
  435.             break;
  436.  
  437.     } while(source->Stream(psnData, chunk_pos));
  438.  
  439. //    OutputDebugString("cache miss\n");
  440. //    _RPT1(0, "cache miss (offset %I64d)\n", chunk_pos);
  441.  
  442.     cache_miss_bytes += len;
  443.  
  444.     while (cache_miss_bytes > 16777216) {
  445.         cache_miss_bytes >>= 1;
  446.         cache_hit_bytes >>= 1;
  447.     }
  448.  
  449.     return source->ReadData(stream, dest, pos, len);
  450. }
  451.  
  452. ///////////////////////////////////////////////////////////////////////////
  453.  
  454. class AVIReadTunnelStream : public IAVIReadStream {
  455. public:
  456.     AVIReadTunnelStream(AVIReadHandler *, PAVISTREAM, IAvisynthClipInfo *pClipInfo);
  457.     ~AVIReadTunnelStream();
  458.  
  459.     HRESULT BeginStreaming(long lStart, long lEnd, long lRate);
  460.     HRESULT EndStreaming();
  461.     HRESULT Info(AVISTREAMINFO *pasi, long lSize);
  462.     bool IsKeyFrame(long lFrame);
  463.     HRESULT Read(long lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples);
  464.     long Start();
  465.     long End();
  466.     long PrevKeyFrame(long lFrame);
  467.     long NextKeyFrame(long lFrame);
  468.     long NearestKeyFrame(long lFrame);
  469.     HRESULT FormatSize(long lFrame, long *plSize);
  470.     HRESULT ReadFormat(long lFrame, void *pFormat, long *plSize);
  471.     bool isStreaming();
  472.     bool isKeyframeOnly();
  473.  
  474. private:
  475.     IAvisynthClipInfo *const pAvisynthClipInfo;
  476.     AVIReadHandler *const parent;
  477.     const PAVISTREAM pas;
  478. };
  479.  
  480. ///////////////////////////////////////////////////////////////////////////
  481.  
  482. AVIReadTunnelStream::AVIReadTunnelStream(AVIReadHandler *_parent, PAVISTREAM _pas, IAvisynthClipInfo *pClipInfo)
  483. : pAvisynthClipInfo(pClipInfo)
  484. , parent(_parent)
  485. , pas(_pas)
  486. {
  487.     parent->AddRef();
  488. }
  489.  
  490. AVIReadTunnelStream::~AVIReadTunnelStream() {
  491.     pas->Release();
  492.     parent->Release();
  493. }
  494.  
  495. HRESULT AVIReadTunnelStream::BeginStreaming(long lStart, long lEnd, long lRate) {
  496.     return AVIStreamBeginStreaming(pas, lStart, lEnd, lRate);
  497. }
  498.  
  499. HRESULT AVIReadTunnelStream::EndStreaming() {
  500.     return AVIStreamEndStreaming(pas);
  501. }
  502.  
  503. HRESULT AVIReadTunnelStream::Info(AVISTREAMINFO *pasi, long lSize) {
  504.     return AVIStreamInfo(pas, pasi, lSize);
  505. }
  506.  
  507. bool AVIReadTunnelStream::IsKeyFrame(long lFrame) {
  508.     return !!AVIStreamIsKeyFrame(pas, lFrame);
  509. }
  510.  
  511. HRESULT AVIReadTunnelStream::Read(long lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples) {
  512.     HRESULT hr;
  513.  
  514.     hr = AVIStreamRead(pas, lStart, lSamples, lpBuffer, cbBuffer, plBytes, plSamples);
  515.  
  516.     if (pAvisynthClipInfo) {
  517.         const char *pszErr;
  518.  
  519.         if (pAvisynthClipInfo->GetError(&pszErr))
  520.             throw MyError("Avisynth read error:\n%s", pszErr);
  521.     }
  522.  
  523.     return hr;
  524. }
  525.  
  526. long AVIReadTunnelStream::Start() {
  527.     return AVIStreamStart(pas);
  528. }
  529.  
  530. long AVIReadTunnelStream::End() {
  531.     return AVIStreamEnd(pas);
  532. }
  533.  
  534. long AVIReadTunnelStream::PrevKeyFrame(long lFrame) {
  535.     return AVIStreamPrevKeyFrame(pas, lFrame);
  536. }
  537.  
  538. long AVIReadTunnelStream::NextKeyFrame(long lFrame) {
  539.     return AVIStreamNextKeyFrame(pas, lFrame);
  540. }
  541.  
  542. long AVIReadTunnelStream::NearestKeyFrame(long lFrame) {
  543.     return AVIStreamNearestKeyFrame(pas, lFrame);
  544. }
  545.  
  546. HRESULT AVIReadTunnelStream::FormatSize(long lFrame, long *plSize) {
  547.     return AVIStreamFormatSize(pas, lFrame, plSize);
  548. }
  549.  
  550. HRESULT AVIReadTunnelStream::ReadFormat(long lFrame, void *pFormat, long *plSize) {
  551.     return AVIStreamReadFormat(pas, lFrame, pFormat, plSize);
  552. }
  553.  
  554. bool AVIReadTunnelStream::isStreaming() {
  555.     return false;
  556. }
  557.  
  558. bool AVIReadTunnelStream::isKeyframeOnly() {
  559.    return false;
  560. }
  561.  
  562. ///////////////////////////////////////////////////////////////////////////
  563.  
  564. class AVIReadStream : public IAVIReadStream, public ListNode2<AVIReadStream> {
  565.     friend AVIReadHandler;
  566.  
  567. public:
  568.     AVIReadStream(AVIReadHandler *, AVIStreamNode *, int);
  569.     ~AVIReadStream();
  570.  
  571.     HRESULT BeginStreaming(long lStart, long lEnd, long lRate);
  572.     HRESULT EndStreaming();
  573.     HRESULT Info(AVISTREAMINFO *pasi, long lSize);
  574.     bool IsKeyFrame(long lFrame);
  575.     HRESULT Read(long lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples);
  576.     long Start();
  577.     long End();
  578.     long PrevKeyFrame(long lFrame);
  579.     long NextKeyFrame(long lFrame);
  580.     long NearestKeyFrame(long lFrame);
  581.     HRESULT FormatSize(long lFrame, long *plSize);
  582.     HRESULT ReadFormat(long lFrame, void *pFormat, long *plSize);
  583.     bool isStreaming();
  584.     bool isKeyframeOnly();
  585.     void Reinit();
  586.  
  587. private:
  588.     AVIReadHandler *parent;
  589.     AVIStreamNode *psnData;
  590.     AVIIndexEntry2 *pIndex;
  591.     AVIReadCache *rCache;
  592.     long& length;
  593.     long& frames;
  594.     long sampsize;
  595.     int streamno;
  596.     bool fStreamingEnabled;
  597.     bool fStreamingActive;
  598.     int iStreamTrackCount;
  599.     long lStreamTrackValue;
  600.     long lStreamTrackInterval;
  601.     bool fRealTime;
  602.  
  603.     __int64        i64CachedPosition;
  604.     AVIIndexEntry2    *pCachedEntry;
  605.  
  606. };
  607.  
  608. ///////////////////////////////////////////////////////////////////////////
  609.  
  610. AVIReadStream::AVIReadStream(AVIReadHandler *parent, AVIStreamNode *psnData, int streamno)
  611. :length(psnData->length)
  612. ,frames(psnData->frames)
  613. {
  614.     this->parent = parent;
  615.     this->psnData = psnData;
  616.     this->streamno = streamno;
  617.  
  618.     fStreamingEnabled = false;
  619.     fStreamingActive = false;
  620.     fRealTime = false;
  621.  
  622.     parent->AddRef();
  623.  
  624.     pIndex = psnData->index.index2Ptr();
  625.     sampsize = psnData->hdr.dwSampleSize;
  626.  
  627.     // Hack to imitate Microsoft's parser.  It seems to ignore this value
  628.     // for audio streams.
  629.  
  630.     if (psnData->hdr.fccType == streamtypeAUDIO)
  631.         sampsize = ((WAVEFORMATEX *)psnData->pFormat)->nBlockAlign;
  632.  
  633.     if (sampsize) {
  634.         i64CachedPosition = 0;
  635.         pCachedEntry = pIndex;
  636.     }
  637.  
  638.     psnData->listHandlers.AddTail(this);
  639. }
  640.  
  641. AVIReadStream::~AVIReadStream() {
  642.     EndStreaming();
  643.     parent->Release();
  644.     Remove();
  645. }
  646.  
  647. void AVIReadStream::Reinit() {
  648.     pIndex = psnData->index.index2Ptr();
  649.     i64CachedPosition = 0;
  650.     pCachedEntry = pIndex;
  651. }
  652.  
  653. HRESULT AVIReadStream::BeginStreaming(long lStart, long lEnd, long lRate) {
  654.     if (fStreamingEnabled)
  655.         return 0;
  656.  
  657. //    OutputDebugString(lRate>1500 ? "starting: fast" : "starting: slow");
  658.  
  659.     if (lRate <= 1500) {
  660.         parent->AdjustRealTime(true);
  661.         fRealTime = true;
  662.     } else
  663.         fRealTime = false;
  664.  
  665.     if (parent->fDisableFastIO)
  666.         return 0;
  667.  
  668.     if (!psnData->streaming_count) {
  669. //        if (!(psnData->cache = new AVIReadCache(psnData->hdr.fccType == 'sdiv' ? 65536 : 16384, streamno, parent, psnData)))
  670. //            return AVIERR_MEMORY;
  671.  
  672.         psnData->stream_bytes = 0;
  673.         psnData->stream_pushes = 0;
  674.         psnData->stream_push_pos = 0;
  675.     }
  676.     ++psnData->streaming_count;
  677.  
  678.     fStreamingEnabled = true;
  679.     fStreamingActive = false;
  680.     iStreamTrackCount = 0;
  681.     lStreamTrackValue = -1;
  682.     lStreamTrackInterval = -1;
  683.     return 0;
  684. }
  685.  
  686. HRESULT AVIReadStream::EndStreaming() {
  687.     if (!fStreamingEnabled)
  688.         return 0;
  689.  
  690.     if (fRealTime)
  691.         parent->AdjustRealTime(false);
  692.  
  693.     if (fStreamingActive)
  694.         parent->DisableStreaming(streamno);
  695.  
  696.     fStreamingEnabled = false;
  697.     fStreamingActive = false;
  698.  
  699.     if (!--psnData->streaming_count) {
  700.         delete psnData->cache;
  701.         psnData->cache = NULL;
  702.     }
  703.     return 0;
  704. }
  705.  
  706. HRESULT AVIReadStream::Info(AVISTREAMINFO *pasi, long lSize) {
  707.     AVISTREAMINFO asi;
  708.  
  709.     memset(&asi, 0, sizeof asi);
  710.  
  711.     asi.fccType                = psnData->hdr.fccType;
  712.     asi.fccHandler            = psnData->hdr.fccHandler;
  713.     asi.dwFlags                = psnData->hdr.dwFlags;
  714.     asi.wPriority            = psnData->hdr.wPriority;
  715.     asi.wLanguage            = psnData->hdr.wLanguage;
  716.     asi.dwScale                = psnData->hdr.dwScale;
  717.     asi.dwRate                = psnData->hdr.dwRate;
  718.     asi.dwStart                = psnData->hdr.dwStart;
  719.     asi.dwLength            = psnData->hdr.dwLength;
  720.     asi.dwInitialFrames        = psnData->hdr.dwInitialFrames;
  721.     asi.dwSuggestedBufferSize = psnData->hdr.dwSuggestedBufferSize;
  722.     asi.dwQuality            = psnData->hdr.dwQuality;
  723.     asi.dwSampleSize        = psnData->hdr.dwSampleSize;
  724.     asi.rcFrame.top            = psnData->hdr.rcFrame.top;
  725.     asi.rcFrame.left        = psnData->hdr.rcFrame.left;
  726.     asi.rcFrame.right        = psnData->hdr.rcFrame.right;
  727.     asi.rcFrame.bottom        = psnData->hdr.rcFrame.bottom;
  728.  
  729.     if (lSize < sizeof asi)
  730.         memcpy(pasi, &asi, lSize);
  731.     else {
  732.         memcpy(pasi, &asi, sizeof asi);
  733.         memset((char *)pasi + sizeof asi, 0, lSize - sizeof asi);
  734.     }
  735.  
  736.     return 0;
  737. }
  738.  
  739. bool AVIReadStream::IsKeyFrame(long lFrame) {
  740.     if (sampsize)
  741.         return true;
  742.     else {
  743.         if (lFrame < 0 || lFrame >= length)
  744.             return false;
  745.  
  746.         return !(pIndex[lFrame].size & 0x80000000);
  747.     }
  748. }
  749.  
  750. HRESULT AVIReadStream::Read(long lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples) {
  751.     long lActual;
  752.  
  753.     if (lStart < 0 || lStart >= length || (lSamples <= 0 && lSamples != AVISTREAMREAD_CONVENIENT)) {
  754.         // umm... dummy!  can't read outside of stream!
  755.  
  756.         if (plBytes) *plBytes = 0;
  757.         if (plSamples) *plSamples = 0;
  758.  
  759.         return 0;
  760.     }
  761.  
  762.     // blocked or discrete?
  763.  
  764.     if (sampsize) {
  765.         AVIIndexEntry2 *avie2, *avie2_limit = pIndex+frames;
  766.         __int64 byte_off = (__int64)lStart * sampsize;
  767.         __int64 bytecnt;
  768.         __int64 actual_bytes=0;
  769.         __int64 block_pos;
  770.  
  771.         // too small to hold a sample?
  772.  
  773.         if (lpBuffer && cbBuffer < sampsize) {
  774.             if (plBytes) *plBytes = sampsize * lSamples;
  775.             if (plSamples) *plSamples = lSamples;
  776.  
  777.             return AVIERR_BUFFERTOOSMALL;
  778.         }
  779.  
  780.         // find the frame that has the starting sample -- try and work
  781.         // from our last position to save time
  782.  
  783.         if (byte_off >= i64CachedPosition) {
  784.             block_pos = i64CachedPosition;
  785.             avie2 = pCachedEntry;
  786.             byte_off -= block_pos;
  787.         } else {
  788.             block_pos = 0;
  789.             avie2 = pIndex;
  790.         }
  791.  
  792.         while(byte_off >= (avie2->size & 0x7FFFFFFF)) {
  793.             byte_off -= (avie2->size & 0x7FFFFFFF);
  794.             block_pos += (avie2->size & 0x7FFFFFFF);
  795.             ++avie2;
  796.         }
  797.  
  798.         pCachedEntry = avie2;
  799.         i64CachedPosition = block_pos;
  800.  
  801.         // Client too lazy to specify a size?
  802.  
  803.         if (lSamples == AVISTREAMREAD_CONVENIENT) {
  804.             lSamples = ((avie2->size & 0x7FFFFFFF) - (long)byte_off) / sampsize;
  805.  
  806.             if (!lSamples && avie2+1 < avie2_limit)
  807.                 lSamples = ((avie2[0].size & 0x7FFFFFFF) + (avie2[1].size & 0x7FFFFFFF) - (long)byte_off) / sampsize;
  808.  
  809.             if (lSamples < 0)
  810.                 lSamples = 1;
  811.         }
  812.  
  813.         // trim down sample count
  814.  
  815.         if (lpBuffer && lSamples > cbBuffer / sampsize)
  816.             lSamples = cbBuffer / sampsize;
  817.  
  818.         if (lStart+lSamples > length)
  819.             lSamples = length - lStart;
  820.  
  821.         bytecnt = lSamples * sampsize;
  822.  
  823.         // begin reading frames from this point on
  824.  
  825.         if (lpBuffer) {
  826.             // detect streaming
  827.  
  828.             if (fStreamingEnabled) {
  829.  
  830.                 // We consider the client to be streaming if we detect at least
  831.                 // 3 consecutive accesses
  832.  
  833.                 if (lStart == lStreamTrackValue) {
  834.                     ++iStreamTrackCount;
  835.  
  836.                     if (iStreamTrackCount >= 15) {
  837.  
  838.                         __int64 streamptr = parent->getStreamPtr();
  839.                         __int64 fptrdiff = streamptr - avie2->pos;
  840.  
  841.                         if (!parent->isStreaming() || streamptr<0 || (fptrdiff<4194304 && fptrdiff>-4194304)) {
  842.                             if (!psnData->cache)
  843.                                 psnData->cache = new AVIReadCache(psnData->hdr.fccType == 'sdiv' ? 131072 : 16384, streamno, parent, psnData);
  844.                             else
  845.                                 psnData->cache->ResetStatistics();
  846.  
  847.                             if (!fStreamingActive) {
  848.                                 fStreamingActive = true;
  849.                                 parent->EnableStreaming(streamno);
  850.                             }
  851.  
  852. #ifdef STREAMING_DEBUG
  853.                             OutputDebugString("[a] streaming enabled\n");
  854. #endif
  855.                         }
  856.                     } else {
  857. #ifdef STREAMING_DEBUG
  858.                         OutputDebugString("[a] streaming detected\n");
  859. #endif
  860.                     }
  861.                 } else {
  862. #ifdef STREAMING_DEBUG
  863.                     OutputDebugString("[a] streaming disabled\n");
  864. #endif
  865.                     iStreamTrackCount = 0;
  866.  
  867.                     if (fStreamingActive) {
  868.                         fStreamingActive = false;
  869.                         parent->DisableStreaming(streamno);
  870.                     }
  871.                 }
  872.             }
  873.  
  874.             while(bytecnt > 0) {
  875.                 long tc;
  876.  
  877.                 tc = (avie2->size & 0x7FFFFFFF) - (long)byte_off;
  878.                 if (tc > bytecnt)
  879.                     tc = (long)bytecnt;
  880.  
  881.                 if (psnData->cache) {
  882. //OutputDebugString("[a] attempting cached read\n");
  883.                     lActual = psnData->cache->Read(lpBuffer, avie2->pos, avie2->pos + byte_off + 8, tc);
  884.                     psnData->stream_bytes += lActual;
  885.                 } else
  886.                     lActual = parent->ReadData(streamno, lpBuffer, avie2->pos + byte_off + 8, tc);
  887.  
  888.                 if (lActual < 0)
  889.                     break;
  890.  
  891.                 actual_bytes += lActual;
  892.                 ++avie2;
  893.                 byte_off = 0;
  894.  
  895.                 if (lActual < tc)
  896.                     break;
  897.  
  898.                 bytecnt -= tc;
  899.                 lpBuffer = (char *)lpBuffer + tc;
  900.             }
  901.  
  902.             if (actual_bytes < sampsize) {
  903.                 if (plBytes) *plBytes = 0;
  904.                 if (plSamples) *plSamples = 0;
  905.                 return AVIERR_FILEREAD;
  906.             }
  907.  
  908.             actual_bytes -= actual_bytes % sampsize;
  909.  
  910.             if (plBytes) *plBytes = (long)actual_bytes;
  911.             if (plSamples) *plSamples = (long)actual_bytes / sampsize;
  912.  
  913.             lStreamTrackValue = lStart + (long)actual_bytes / sampsize;
  914.  
  915.         } else {
  916.             if (plBytes) *plBytes = (long)bytecnt;
  917.             if (plSamples) *plSamples = lSamples;
  918.         }
  919.  
  920.     } else {
  921.         AVIIndexEntry2 *avie2 = &pIndex[lStart];
  922.  
  923.         if (lpBuffer && (avie2->size & 0x7FFFFFFF) > cbBuffer) {
  924.             if (plBytes) *plBytes = avie2->size & 0x7FFFFFFF;
  925.             if (plSamples) *plSamples = 1;
  926.  
  927.             return AVIERR_BUFFERTOOSMALL;
  928.         }
  929.  
  930.         if (lpBuffer) {
  931.  
  932.             // detect streaming
  933.  
  934.             if (fStreamingEnabled && lStart != lStreamTrackValue) {
  935.                 if (lStreamTrackValue>=0 && lStart-lStreamTrackValue == lStreamTrackInterval) {
  936.                     if (++iStreamTrackCount >= 15) {
  937.  
  938.                         __int64 streamptr = parent->getStreamPtr();
  939.                         __int64 fptrdiff = streamptr - avie2->pos;
  940.  
  941.                         if (!parent->isStreaming() || streamptr<0 || (fptrdiff<4194304 && fptrdiff>-4194304)) {
  942.                             if (!psnData->cache)
  943.                                 psnData->cache = new AVIReadCache(psnData->hdr.fccType == 'sdiv' ? 131072 : 16384, streamno, parent, psnData);
  944.                             else
  945.                                 psnData->cache->ResetStatistics();
  946.  
  947.                             if (!fStreamingActive) {
  948.                                 fStreamingActive = true;
  949.                                 parent->EnableStreaming(streamno);
  950.                             }
  951.  
  952. #ifdef STREAMING_DEBUG
  953.                             OutputDebugString("[v] streaming activated\n");
  954. #endif
  955.                         }
  956.                     } else {
  957. #ifdef STREAMING_DEBUG
  958.                         OutputDebugString("[v] streaming detected\n");
  959. #endif
  960.                     }
  961.                 } else {
  962.                     iStreamTrackCount = 0;
  963. #ifdef STREAMING_DEBUG
  964.                     OutputDebugString("[v] streaming disabled\n");
  965. #endif
  966.                     if (lStreamTrackValue>=0 && lStart > lStreamTrackValue) {
  967.                         lStreamTrackInterval = lStart - lStreamTrackValue;
  968.                     } else
  969.                         lStreamTrackInterval = -1;
  970.  
  971.                     if (fStreamingActive) {
  972.                         fStreamingActive = false;
  973.                         parent->DisableStreaming(streamno);
  974.                     }
  975.                 }
  976.                         
  977.                 lStreamTrackValue = lStart;
  978.             }
  979.  
  980.             // read data
  981.  
  982.             if (psnData->cache && fStreamingActive) {
  983. //OutputDebugString("[v] attempting cached read\n");
  984.                 lActual = psnData->cache->Read(lpBuffer, avie2->pos, avie2->pos + 8, avie2->size & 0x7FFFFFFF);
  985.                 psnData->stream_bytes += lActual;
  986.             } else
  987.                 lActual = parent->ReadData(streamno, lpBuffer, avie2->pos+8, avie2->size & 0x7FFFFFFF);
  988.  
  989.             if (lActual != (avie2->size & 0x7FFFFFFF)) {
  990.                 if (plBytes) *plBytes = 0;
  991.                 if (plSamples) *plSamples = 0;
  992.                 return AVIERR_FILEREAD;
  993.             }
  994.         }
  995.  
  996.         if (plBytes) *plBytes = avie2->size & 0x7FFFFFFF;
  997.         if (plSamples) *plSamples = 1;
  998.     }
  999.  
  1000.     if (psnData->cache && fStreamingActive) {
  1001.  
  1002.         // Are we experiencing a high rate of cache misses?
  1003.  
  1004.         if (psnData->cache->cache_miss_bytes*2 > psnData->cache->cache_hit_bytes && psnData->cache->reads > 50) {
  1005.  
  1006.             // sh*t, notify the parent that we have cache misses so it can check which stream is
  1007.             // screwing up, and disable streaming on feeds that are too far off
  1008.  
  1009.             parent->FixCacheProblems(this);
  1010.             iStreamTrackCount = 0;
  1011.         }
  1012.     }/* else if (fStreamingEnabled) {
  1013.  
  1014.         // hmm... our cache got killed!
  1015.  
  1016.         iStreamTrackCount = 0;
  1017.  
  1018.     }*/
  1019.  
  1020.     return 0;
  1021. }
  1022.  
  1023. long AVIReadStream::Start() {
  1024.     return 0;
  1025. }
  1026.  
  1027. long AVIReadStream::End() {
  1028.     return length;
  1029. }
  1030.  
  1031. long AVIReadStream::PrevKeyFrame(long lFrame) {
  1032.     if (sampsize)
  1033.         return lFrame>0 ? lFrame-1 : -1;
  1034.  
  1035.     if (lFrame < 0)
  1036.         return -1;
  1037.  
  1038.     if (lFrame >= length)
  1039.         lFrame = length;
  1040.  
  1041.     while(--lFrame > 0)
  1042.         if (!(pIndex[lFrame].size & 0x80000000))
  1043.             return lFrame;
  1044.  
  1045.     return -1;
  1046. }
  1047.  
  1048. long AVIReadStream::NextKeyFrame(long lFrame) {
  1049.     if (sampsize)
  1050.         return lFrame<length ? lFrame+1 : -1;
  1051.  
  1052.     if (lFrame < 0)
  1053.         return 0;
  1054.  
  1055.     if (lFrame >= length)
  1056.         return -1;
  1057.  
  1058.     while(++lFrame < length)
  1059.         if (!(pIndex[lFrame].size & 0x80000000))
  1060.             return lFrame;
  1061.  
  1062.     return -1;
  1063. }
  1064.  
  1065. long AVIReadStream::NearestKeyFrame(long lFrame) {
  1066.     long lprev;
  1067.  
  1068.     if (sampsize)
  1069.         return lFrame;
  1070.  
  1071.     if (IsKeyFrame(lFrame))
  1072.         return lFrame;
  1073.  
  1074.     lprev = PrevKeyFrame(lFrame);
  1075.  
  1076.     if (lprev < 0)
  1077.         return 0;
  1078.     else
  1079.         return lprev;
  1080. }
  1081.  
  1082. HRESULT AVIReadStream::FormatSize(long lFrame, long *plSize) {
  1083.     *plSize = psnData->lFormatLen;
  1084.     return 0;
  1085. }
  1086.  
  1087. HRESULT AVIReadStream::ReadFormat(long lFrame, void *pFormat, long *plSize) {
  1088.     if (!pFormat) {
  1089.         *plSize = psnData->lFormatLen;
  1090.         return 0;
  1091.     }
  1092.  
  1093.     if (*plSize < psnData->lFormatLen) {
  1094.         memcpy(pFormat, psnData->pFormat, *plSize);
  1095.     } else {
  1096.         memcpy(pFormat, psnData->pFormat, psnData->lFormatLen);
  1097.         *plSize = psnData->lFormatLen;
  1098.     }
  1099.  
  1100.     return 0;
  1101. }
  1102.  
  1103. bool AVIReadStream::isStreaming() {
  1104.     return psnData->cache && fStreamingActive;
  1105. }
  1106.  
  1107. bool AVIReadStream::isKeyframeOnly() {
  1108.    return psnData->keyframe_only;
  1109. }
  1110.  
  1111. ///////////////////////////////////////////////////////////////////////////
  1112.  
  1113. AVIReadHandler::AVIReadHandler(const char *s)
  1114. : pAvisynthClipInfo(0)
  1115. {
  1116.     this->hFile = INVALID_HANDLE_VALUE;
  1117.     this->hFileUnbuffered = INVALID_HANDLE_VALUE;
  1118.     this->paf = NULL;
  1119.     ref_count = 1;
  1120.     streams=0;
  1121.     fStreamsActive = 0;
  1122.     fDisableFastIO = false;
  1123.     streamBuffer = NULL;
  1124.     nRealTime = 0;
  1125.     nActiveStreamers = 0;
  1126.     fFakeIndex = false;
  1127.     nFiles = 1;
  1128.     nCurrentFile = 0;
  1129.     pSegmentHint = NULL;
  1130.  
  1131.     if (!g_disklockinited) {
  1132.         g_disklockinited=true;
  1133.         InitializeCriticalSection(&g_diskcs);
  1134.     }
  1135.  
  1136.     _construct(s);
  1137. }
  1138.  
  1139. AVIReadHandler::AVIReadHandler(PAVIFILE paf) {
  1140.     this->hFile = INVALID_HANDLE_VALUE;
  1141.     this->hFileUnbuffered = INVALID_HANDLE_VALUE;
  1142.     this->paf = paf;
  1143.     ref_count = 1;
  1144.     streams=0;
  1145.     streamBuffer = NULL;
  1146.     pSegmentHint = NULL;
  1147.     fFakeIndex = false;
  1148.  
  1149.     if (FAILED(paf->QueryInterface(IID_IAvisynthClipInfo, (void **)&pAvisynthClipInfo)))
  1150.         pAvisynthClipInfo = NULL;
  1151.     else {
  1152.         const char *s;
  1153.  
  1154.         if (pAvisynthClipInfo->GetError(&s)) {
  1155.             MyError e("Avisynth open failure:\n%s", s);
  1156.             pAvisynthClipInfo->Release();
  1157.             paf->Release();
  1158.             throw e;
  1159.         }
  1160.     }
  1161. }
  1162.  
  1163. AVIReadHandler::~AVIReadHandler() {
  1164.     _destruct();
  1165. }
  1166.  
  1167. void AVIReadHandler::_construct(const char *pszFile) {
  1168.  
  1169.     try {
  1170.         AVIFileDesc *pDesc;
  1171.  
  1172.         // open file
  1173.  
  1174.         hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  1175.  
  1176.         if (INVALID_HANDLE_VALUE == hFile)
  1177.             throw MyWin32Error("Couldn't open %s: %%s", GetLastError(), pszFile);
  1178.  
  1179.         hFileUnbuffered = CreateFile(
  1180.                 pszFile,
  1181.                 GENERIC_READ,
  1182.                 FILE_SHARE_READ,
  1183.                 NULL,
  1184.                 OPEN_EXISTING,
  1185.                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
  1186.                 NULL
  1187.             );
  1188.  
  1189.         i64FilePosition = 0;
  1190.  
  1191.         // recursively parse file
  1192.  
  1193.         _parseFile(listStreams);
  1194.  
  1195.         // Create first link
  1196.  
  1197.         if (!(pDesc = new AVIFileDesc))
  1198.             throw MyMemoryError();
  1199.  
  1200.         pDesc->hFile            = hFile;
  1201.         pDesc->hFileUnbuffered    = hFileUnbuffered;
  1202.         pDesc->i64Size            = i64Size = _sizeFile();
  1203.  
  1204.         listFiles.AddHead(pDesc);
  1205.  
  1206.     } catch(...) {
  1207.         _destruct();
  1208.         throw;
  1209.     }
  1210. }
  1211.  
  1212. bool AVIReadHandler::AppendFile(const char *pszFile) {
  1213.     List2<AVIStreamNode> newstreams;
  1214.     AVIStreamNode *pasn_old, *pasn_new, *pasn_old_next=NULL, *pasn_new_next=NULL;
  1215.     AVIFileDesc *pDesc;
  1216.  
  1217.     nCurrentFile = -1;
  1218.  
  1219.     // open file
  1220.  
  1221.     hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  1222.  
  1223.     if (INVALID_HANDLE_VALUE == hFile)
  1224.         throw MyWin32Error("Couldn't open %s: %%s", GetLastError(), pszFile);
  1225.  
  1226.     hFileUnbuffered = CreateFile(
  1227.             pszFile,
  1228.             GENERIC_READ,
  1229.             FILE_SHARE_READ,
  1230.             NULL,
  1231.             OPEN_EXISTING,
  1232.             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
  1233.             NULL
  1234.         );
  1235.  
  1236.     try {
  1237.         _parseFile(newstreams);
  1238.  
  1239.         pasn_old = listStreams.AtHead();
  1240.         pasn_new = newstreams.AtHead();
  1241.  
  1242.         while(!!(pasn_old_next = pasn_old->NextFromHead()) & !!(pasn_new_next = pasn_new->NextFromHead())) {
  1243.             const char *szPrefix;
  1244.  
  1245.             switch(pasn_old->hdr.fccType) {
  1246.             case streamtypeAUDIO:    szPrefix = "Cannot append segment: The audio streams "; break;
  1247.             case streamtypeVIDEO:    szPrefix = "Cannot append segment: The video streams "; break;
  1248.             default:                szPrefix = NULL;
  1249.             }
  1250.  
  1251.             // If it's not an audio or video stream, why do we care?
  1252.  
  1253.             if (szPrefix) {
  1254.                 if (pasn_old->hdr.fccType != pasn_new->hdr.fccType)
  1255.                     throw MyError("Cannot append segment: The stream types do not count.");
  1256.  
  1257.                 if (pasn_old->hdr.fccHandler != pasn_new->hdr.fccHandler)
  1258.                     throw MyError("%suse incompatible compression types.", szPrefix);
  1259.  
  1260.                 // A/B ?= C/D ==> AD ?= BC
  1261.  
  1262.                 if ((__int64)pasn_old->hdr.dwScale * pasn_new->hdr.dwRate != (__int64)pasn_new->hdr.dwScale * pasn_old->hdr.dwRate)
  1263.                     throw MyError("%shave different sampling rates (%.5f vs. %.5f)"
  1264.                             ,szPrefix
  1265.                             ,(double)pasn_old->hdr.dwRate / pasn_old->hdr.dwScale
  1266.                             ,(double)pasn_new->hdr.dwRate / pasn_new->hdr.dwScale
  1267.                             );
  1268.  
  1269.                 if (pasn_old->hdr.dwSampleSize != pasn_new->hdr.dwSampleSize)
  1270.                     throw MyError("%shave different block sizes (%d vs %d).", szPrefix, pasn_old->hdr.dwSampleSize, pasn_new->hdr.dwSampleSize);
  1271.  
  1272.                 // I hate PCMWAVEFORMAT.
  1273.  
  1274.                 bool fOk = pasn_old->lFormatLen == pasn_new->lFormatLen && !memcmp(pasn_old->pFormat, pasn_new->pFormat, pasn_old->lFormatLen);
  1275.  
  1276.                 if (pasn_old->hdr.fccType == streamtypeAUDIO)
  1277.                     if (((WAVEFORMATEX *)pasn_old->pFormat)->wFormatTag == WAVE_FORMAT_PCM
  1278.                         && ((WAVEFORMATEX *)pasn_new->pFormat)->wFormatTag == WAVE_FORMAT_PCM)
  1279.                             fOk = !memcmp(pasn_old->pFormat, pasn_new->pFormat, sizeof(PCMWAVEFORMAT));
  1280.  
  1281.                 if (!fOk)
  1282.                     throw MyError("%shave different data formats.", szPrefix);
  1283.             }
  1284.  
  1285.             pasn_old = pasn_old_next;
  1286.             pasn_new = pasn_new_next;
  1287.         }
  1288.  
  1289.         if (pasn_old_next || pasn_new_next)
  1290.             throw MyError("Cannot append segment: The segment has a different number of streams.");
  1291.  
  1292.         if (!(pDesc = new AVIFileDesc))
  1293.             throw MyMemoryError();
  1294.  
  1295.         pDesc->hFile            = hFile;
  1296.         pDesc->hFileUnbuffered    = hFileUnbuffered;
  1297.         pDesc->i64Size            = _sizeFile();
  1298.     } catch(MyError e) {
  1299.         while(pasn_new = newstreams.RemoveHead())
  1300.             delete pasn_new;
  1301.  
  1302.         CloseHandle(hFile);
  1303.         if (hFileUnbuffered != INVALID_HANDLE_VALUE)
  1304.             CloseHandle(hFileUnbuffered);
  1305.  
  1306.         throw;
  1307.     }
  1308.  
  1309.     // Accept segment; begin merging process.
  1310.  
  1311.     pasn_old = listStreams.AtHead();
  1312.  
  1313.     while(pasn_old_next = pasn_old->NextFromHead()) {
  1314.         pasn_new = newstreams.RemoveHead();
  1315.  
  1316.         // Fix up header.
  1317.  
  1318.         pasn_old->hdr.dwLength    += pasn_new->hdr.dwLength;
  1319.  
  1320.         if (pasn_new->hdr.dwSuggestedBufferSize > pasn_old->hdr.dwSuggestedBufferSize)
  1321.             pasn_old->hdr.dwSuggestedBufferSize = pasn_new->hdr.dwSuggestedBufferSize;
  1322.  
  1323.         pasn_old->bytes        += pasn_new->bytes;
  1324.         pasn_old->frames    += pasn_new->frames;
  1325.         pasn_old->length    += pasn_new->length;
  1326.  
  1327.         // Merge indices.
  1328.  
  1329.         int oldlen = pasn_old->index.indexLen();
  1330.         AVIIndexEntry2 *idx_old = pasn_old->index.takeIndex2();
  1331.         AVIIndexEntry2 *idx_new = pasn_new->index.index2Ptr();
  1332.         int i;
  1333.  
  1334.         pasn_old->index.clear();
  1335.  
  1336.         for(i=0; i<oldlen; i++) {
  1337.             idx_old[i].size ^= 0x80000000;
  1338.             pasn_old->index.add(&idx_old[i]);
  1339.         }
  1340.  
  1341.         delete[] idx_old;
  1342.  
  1343.         for(i=pasn_new->index.indexLen(); i; i--) {
  1344.             idx_new->size ^= 0x80000000;
  1345.             idx_new->pos += (__int64)nFiles << 48;
  1346.             pasn_old->index.add(idx_new++);
  1347.         }
  1348.  
  1349.         pasn_old->index.makeIndex2();
  1350.  
  1351.         // Notify all handlers.
  1352.  
  1353.         AVIReadStream *pStream, *pStreamNext;
  1354.  
  1355.         pStream = pasn_old->listHandlers.AtHead();
  1356.         while(pStreamNext = pStream->NextFromHead()) {
  1357.             pStream->Reinit();
  1358.  
  1359.             pStream = pStreamNext;
  1360.         }
  1361.  
  1362.         // Next!
  1363.  
  1364.         pasn_old = pasn_old_next;
  1365.         delete pasn_new;
  1366.     }    
  1367.  
  1368.     ++nFiles;
  1369.     listFiles.AddTail(pDesc);
  1370.  
  1371.     return true;
  1372. }
  1373.  
  1374. void AVIReadHandler::_parseFile(List2<AVIStreamNode>& streamlist) {
  1375.     FOURCC fccType;
  1376.     DWORD dwLength;
  1377.     DWORD dwLengthLeft;
  1378.     bool index_found = false;
  1379.     bool size_invalid = false;
  1380.     bool fAcceptIndexOnly = true;
  1381.     bool hyperindexed = false;
  1382.     AVIStreamNode *pasn, *pasn_next;
  1383.  
  1384.     __int64    i64ChunkMoviPos = 0;
  1385.     DWORD    dwChunkMoviLength = 0;
  1386.  
  1387.     if (!_readChunkHeader(fccType, dwLength))
  1388.         throw MyError("Invalid AVI file: File is less than 8 bytes");
  1389.  
  1390.     if (fccType != FOURCC_RIFF)
  1391.         throw MyError("Invalid AVI file: Not a RIFF file");
  1392.  
  1393.     // If the RIFF header is <4 bytes, assume it was an improperly closed
  1394.     // file.
  1395.  
  1396. //    if (dwLength < 4)
  1397. //        throw MyError("Invalid AVI file: RIFF wrapper has invalid size");
  1398.  
  1399.     if (dwLength < 4) {
  1400.         dwLength = 0xFFFFFFF0;
  1401.         size_invalid = true;
  1402.     }
  1403.  
  1404.     dwLengthLeft = dwLength-4;
  1405.  
  1406.     _readFile2(&fccType, 4);
  1407.  
  1408.     if (fccType != ' IVA')
  1409.         throw MyError("Invalid AVI file: RIFF type is not 'AVI'");
  1410.  
  1411.     // begin parsing chunks
  1412.  
  1413.     while(dwLengthLeft >= 8 && _readChunkHeader(fccType, dwLength)) {
  1414.  
  1415. //        _RPT4(0,"%08I64x %08I64x Chunk '%-4s', length %08lx\n", _posFile()+dwLengthLeft, _posFile(), &fccType, dwLength);
  1416.  
  1417.         if (!size_invalid) {
  1418.             dwLengthLeft -= 8;
  1419.  
  1420.             if (dwLength > dwLengthLeft)
  1421.                 throw MyError("Invalid AVI file: chunk at %I64d extends outside of parent by %ld bytes", _posFile()-8, dwLength-dwLengthLeft);
  1422.  
  1423.             dwLengthLeft -= (dwLength + (dwLength&1));
  1424.         }
  1425.  
  1426.         switch(fccType) {
  1427.         case FOURCC_LIST:
  1428.             _readFile2(&fccType, 4);
  1429.  
  1430.             if (dwLength<4 && (fccType != 'ivom' || !size_invalid))
  1431.                 throw MyError("Invalid AVI file: LIST chunk <4 bytes");
  1432.  
  1433.             dwLength -= 4;
  1434.  
  1435. //            _RPT1(0,"\tList type '%-4s'\n", &fccType);
  1436.  
  1437.             switch(fccType) {
  1438.             case 'ivom':
  1439.  
  1440.                 if (dwLength < 8 && size_invalid) {
  1441.                     i64ChunkMoviPos = _posFile();
  1442.                     dwChunkMoviLength = 0xFFFFFFF0;
  1443.                     dwLength = 0;
  1444.                 } else {
  1445.                     i64ChunkMoviPos = _posFile();
  1446.                     dwChunkMoviLength = dwLength;
  1447.                 }
  1448.  
  1449.                 if (fAcceptIndexOnly)
  1450.                     goto terminate_scan;
  1451.  
  1452.                 break;
  1453.             case listtypeAVIHEADER:
  1454.                 dwLengthLeft += (dwLength + (dwLength&1)) + 4;
  1455.                 dwLength = 0;    // silently enter the header block
  1456.                 break;
  1457.             case listtypeSTREAMHEADER:
  1458.                 if (!_parseStreamHeader(streamlist, dwLength))
  1459.                     fAcceptIndexOnly = false;
  1460.                 else
  1461.                     hyperindexed = true;
  1462.  
  1463.                 ++streams;
  1464.                 dwLength = 0;
  1465.                 break;
  1466.             }
  1467.  
  1468.             break;
  1469.  
  1470.         case ckidAVINEWINDEX:    // idx1
  1471.             if (!hyperindexed) {
  1472.                 index_found = _parseIndexBlock(streamlist, dwLength/16, i64ChunkMoviPos);
  1473.                 dwLength &= 15;
  1474.             }
  1475.             break;
  1476.  
  1477.         case ckidAVIPADDING:    // JUNK
  1478.             break;
  1479.  
  1480.         case 'mges':            // VirtualDub segment hint block
  1481.             delete pSegmentHint;
  1482.             if (!(pSegmentHint = new char[dwLength]))
  1483.                 throw MyMemoryError();
  1484.  
  1485.             _readFile2(pSegmentHint, dwLength);
  1486.  
  1487.             if (dwLength&1)
  1488.                 _skipFile2(1);
  1489.  
  1490.             dwLength = 0;
  1491.             break;
  1492.  
  1493.         }
  1494.  
  1495.         if (dwLength) {
  1496.             if (!_skipFile2(dwLength + (dwLength&1)))
  1497.                 break;
  1498.         }
  1499.  
  1500.         // If we're trying to read a broken file, quit as soon as we see the index
  1501.         // block.
  1502.  
  1503.         if (size_invalid && fccType == ckidAVINEWINDEX)
  1504.             break;
  1505.     }
  1506.  
  1507.     if (i64ChunkMoviPos == 0)
  1508.         throw MyError("This AVI file doesn't have a movie data block (movi)!");
  1509.  
  1510. terminate_scan:
  1511.     if (!index_found && !hyperindexed) {
  1512.         ProgressDialog pd(NULL, "AVI Import Filter", "Reconstructing missing index block", (dwChunkMoviLength+1023)/1024, true);
  1513.  
  1514.         pd.setValueFormat("%ldK of %ldK");
  1515.  
  1516.         // obtain length of file and limit scanning if so
  1517.  
  1518.         __int64 i64FileSize = 0x7FFFFFFFFFFFFFFFi64;
  1519.  
  1520.         dwLengthLeft = dwChunkMoviLength;
  1521.  
  1522.         {
  1523.             DWORD dwLow, dwHigh;
  1524.             
  1525.             dwLow = GetFileSize(hFile, &dwHigh);
  1526.  
  1527.             if (dwLow != 0xFFFFFFFF || GetLastError()==NO_ERROR) {
  1528.                 i64FileSize = (__int64)(unsigned long)dwLow + ((__int64)(signed long)dwHigh << 32);
  1529.             }
  1530.         }
  1531.  
  1532.         fFakeIndex = true;
  1533.  
  1534.         _seekFile(i64ChunkMoviPos);
  1535.  
  1536.         while(dwLengthLeft >= 8 && _readChunkHeader(fccType, dwLength)) {
  1537.             int stream;
  1538.             
  1539. //            _RPT2(0,"(stream header) Chunk '%-4s', length %08lx\n", &fccType, dwLength);
  1540.  
  1541.             dwLengthLeft -= 8+(dwLength + (dwLength&1));
  1542.  
  1543.             if (dwLength) {
  1544.                 if (!_skipFile2(dwLength + (dwLength&1)))
  1545.                     break;
  1546.             }
  1547.  
  1548.             if (_posFile() > i64FileSize)
  1549.                 break;
  1550.  
  1551.             if (isxdigit(fccType&0xff) && isxdigit((fccType>>8)&0xff)) {
  1552.                 stream = StreamFromFOURCC(fccType);
  1553.  
  1554.                 if (stream >=0 && stream < streams) {
  1555.  
  1556.                     pasn = streamlist.AtHead();
  1557.  
  1558.                     while(stream-- && (pasn_next = pasn->NextFromHead()))
  1559.                         pasn = pasn_next;
  1560.  
  1561.                     if (pasn && pasn_next) {
  1562.                         pasn->index.add(fccType, _posFile()-(dwLength + (dwLength&1))-8, dwLength, pasn->keyframe_only && pasn->bytes!=0);
  1563.                         pasn->bytes += dwLength;
  1564.                     }
  1565.                 }
  1566.  
  1567.             }
  1568.  
  1569.             pd.advance((long)((_posFile() - i64ChunkMoviPos)/1024));
  1570.             pd.check();
  1571.         }
  1572.  
  1573.     }
  1574.  
  1575.     // glue together indices
  1576.  
  1577.     pasn = streamlist.AtHead();
  1578.  
  1579.     while(pasn_next = pasn->NextFromHead()) {
  1580.         if (!pasn->index.makeIndex2())
  1581.             throw MyMemoryError();
  1582.  
  1583.         pasn->frames = pasn->index.indexLen();
  1584.  
  1585.         // Clear sample size for video streams!
  1586.  
  1587.         if (pasn->hdr.fccType == streamtypeVIDEO)
  1588.             pasn->hdr.dwSampleSize=0;
  1589.  
  1590.         if (pasn->hdr.dwSampleSize)
  1591.             pasn->length = (long)pasn->bytes / pasn->hdr.dwSampleSize;
  1592.         else
  1593.             pasn->length = pasn->frames;
  1594.  
  1595.         pasn = pasn_next;
  1596.     }
  1597.  
  1598. //    throw MyError("Parse complete.  Aborting.");
  1599. }
  1600.  
  1601. bool AVIReadHandler::_parseStreamHeader(List2<AVIStreamNode>& streamlist, DWORD dwLengthLeft) {
  1602.     AVIStreamNode *pasn;
  1603.     FOURCC fccType;
  1604.     DWORD dwLength;
  1605.     bool hyperindexed = false;
  1606.     
  1607.     if (!(pasn = new AVIStreamNode()))
  1608.         throw MyMemoryError();
  1609.  
  1610.     try {
  1611.         while(dwLengthLeft >= 8 && _readChunkHeader(fccType, dwLength)) {
  1612.  
  1613. //            _RPT2(0,"(stream header) Chunk '%-4s', length %08lx\n", &fccType, dwLength);
  1614.  
  1615.             dwLengthLeft -= 8;
  1616.  
  1617.             if (dwLength > dwLengthLeft)
  1618.                 throw MyError("Invalid AVI file: chunk size extends outside of parent");
  1619.  
  1620.             dwLengthLeft -= (dwLength + (dwLength&1));
  1621.  
  1622.             switch(fccType) {
  1623.  
  1624.             case ckidSTREAMHEADER:
  1625.                 memset(&pasn->hdr, 0, sizeof pasn->hdr);
  1626.  
  1627.                 if (dwLength < sizeof pasn->hdr) {
  1628.                     _readFile2(&pasn->hdr, dwLength);
  1629.                     if (dwLength & 1)
  1630.                         _skipFile(1);
  1631.                 } else {
  1632.                     _readFile2(&pasn->hdr, sizeof pasn->hdr);
  1633.                     _skipFile(dwLength+(dwLength&1) - sizeof pasn->hdr);
  1634.                 }
  1635.                 dwLength = 0;
  1636.  
  1637.                 pasn->keyframe_only = false;
  1638.  
  1639.                 break;
  1640.  
  1641.             case ckidSTREAMFORMAT:
  1642.                 if (!(pasn->pFormat = new char[pasn->lFormatLen = dwLength]))
  1643.                     throw MyMemoryError();
  1644.  
  1645.                 _readFile2(pasn->pFormat, dwLength);
  1646.  
  1647.                 if (pasn->hdr.fccType == streamtypeVIDEO) {
  1648.                     switch(((BITMAPINFOHEADER *)pasn->pFormat)->biCompression) {
  1649.                         case NULL:
  1650.                         case ' WAR':
  1651.                         case ' BID':
  1652.                         case '1bmd':
  1653.                         case 'gpjm':
  1654.                         case 'GPJM':
  1655.                         case 'YUYV':
  1656.                         case '2YUY':
  1657.                         case 'YVYU':
  1658.                         case 'UYVY':
  1659.                         case '21VY':
  1660.                         case '024I':
  1661.                         case 'P14Y':
  1662.                         case 'vuyc':
  1663.                         case 'UYFH':
  1664.                             pasn->keyframe_only = true;
  1665.                     }
  1666.                 }
  1667.  
  1668.                 if (dwLength & 1)
  1669.                     _skipFile(1);
  1670.                 dwLength = 0;
  1671.                 break;
  1672.  
  1673.             case 'xdni':            // OpenDML extended index
  1674.                 _parseExtendedIndexBlock(streamlist, pasn, -1, dwLength);
  1675.                 hyperindexed = true;
  1676.                 break;
  1677.  
  1678.             case ckidAVIPADDING:    // JUNK
  1679.                 break;
  1680.             }
  1681.  
  1682.             if (dwLength) {
  1683.                 if (!_skipFile2(dwLength + (dwLength&1)))
  1684.                     break;
  1685.             }
  1686.         }
  1687.  
  1688.         if (dwLengthLeft)
  1689.             _skipFile2(dwLengthLeft);
  1690.     } catch(...) {
  1691.         delete pasn;
  1692.         throw;
  1693.     }
  1694.  
  1695. //    _RPT1(0,"Found stream: type %s\n", pasn->hdr.fccType==streamtypeVIDEO ? "video" : pasn->hdr.fccType==streamtypeAUDIO ? "audio" : "unknown");
  1696.  
  1697.     streamlist.AddTail(pasn);
  1698.  
  1699.     return hyperindexed;
  1700. }
  1701.  
  1702. bool AVIReadHandler::_parseIndexBlock(List2<AVIStreamNode>& streamlist, int count, __int64 movi_offset) {
  1703.     AVIINDEXENTRY avie[32];
  1704.     AVIStreamNode *pasn, *pasn_next;
  1705.     bool absolute_addr = true;
  1706.  
  1707.     // Some AVI files have relative addresses in their AVI index chunks, and some
  1708.     // relative.  They're supposed to be relative to the 'movi' chunk; all versions
  1709.     // of VirtualDub using fast write routines prior to build 4936 generate absolute
  1710.     // addresses (oops). AVIFile and ActiveMovie are both ambivalent.  I guess we'd
  1711.     // better be as well.
  1712.  
  1713.     while(count > 0) {
  1714.         int tc = count;
  1715.         int i;
  1716.  
  1717.         if (tc>32) tc=32;
  1718.         count -= tc;
  1719.  
  1720.         if (tc*sizeof(AVIINDEXENTRY) != _readFile(avie, tc*sizeof(AVIINDEXENTRY))) {
  1721.             pasn = streamlist.AtHead();
  1722.  
  1723.             while(pasn_next = pasn->NextFromHead()) {
  1724.                 pasn->index.clear();
  1725.                 pasn->bytes = 0;
  1726.  
  1727.                 pasn = pasn_next;
  1728.             }
  1729.             return false;
  1730.         }
  1731.  
  1732.         for(i=0; i<tc; i++) {
  1733.             int stream = StreamFromFOURCC(avie[i].ckid);
  1734.  
  1735.             if (absolute_addr && avie[i].dwChunkOffset<movi_offset)
  1736.                 absolute_addr = false;
  1737.  
  1738.             pasn = streamlist.AtHead();
  1739.  
  1740.             while((pasn_next = (AVIStreamNode *)pasn->NextFromHead()) && stream--)
  1741.                 pasn = pasn_next;
  1742.  
  1743.             if (pasn && pasn_next) {
  1744.                 if (absolute_addr)
  1745.                     pasn->index.add(&avie[i]);
  1746.                 else
  1747.                     pasn->index.add(avie[i].ckid, (movi_offset-4) + (__int64)avie[i].dwChunkOffset, avie[i].dwChunkLength, !!(avie[i].dwFlags & AVIIF_KEYFRAME));
  1748.  
  1749.                 pasn->bytes += avie[i].dwChunkLength;
  1750.             }
  1751.         }
  1752.     }
  1753.  
  1754.     return true;
  1755.  
  1756. }
  1757.  
  1758. void AVIReadHandler::_parseExtendedIndexBlock(List2<AVIStreamNode>& streamlist, AVIStreamNode *pasn, __int64 fpos, DWORD dwLength) {
  1759.     union {
  1760.         AVISUPERINDEX idxsuper;
  1761.         AVISTDINDEX idxstd;
  1762.     };
  1763.  
  1764.     union {
  1765.         struct    _avisuperindex_entry        superent[64];
  1766.         DWORD    dwHeap[256];
  1767.     };
  1768.  
  1769.     int entries, tp;
  1770.     int i;
  1771.     __int64 i64FPSave = _posFile();
  1772.  
  1773.     if (fpos>=0)
  1774.         _seekFile(fpos);
  1775.     _readFile2((char *)&idxsuper + 8, sizeof(AVISUPERINDEX) - 8);
  1776.  
  1777.     switch(idxsuper.bIndexType) {
  1778.     case AVI_INDEX_OF_INDEXES:
  1779.         // sanity check
  1780.  
  1781.         if (idxsuper.wLongsPerEntry != 4)
  1782.             throw MyError("Invalid superindex block in stream");
  1783.  
  1784. //        if (idxsuper.bIndexSubType != 0)
  1785. //            throw MyError("Field indexes not supported");
  1786.  
  1787.         entries = idxsuper.nEntriesInUse;
  1788.  
  1789.         while(entries > 0) {
  1790.             tp = sizeof superent / sizeof superent[0];
  1791.             if (tp>entries) tp=entries;
  1792.  
  1793.             _readFile2(superent, tp*sizeof superent[0]);
  1794.  
  1795.             for(i=0; i<tp; i++)
  1796.                 _parseExtendedIndexBlock(streamlist, pasn, superent[i].qwOffset+8, superent[i].dwSize-8);
  1797.  
  1798.             entries -= tp;
  1799.         }
  1800.  
  1801.         break;
  1802.  
  1803.     case AVI_INDEX_OF_CHUNKS:
  1804.  
  1805. //        if (idxstd.bIndexSubType != 0)
  1806. //            throw MyError("Frame indexes not supported");
  1807.  
  1808.         entries = idxstd.nEntriesInUse;
  1809.  
  1810.         // In theory, if bIndexSubType==AVI_INDEX_2FIELD it's supposed to have
  1811.         // wLongsPerEntry=3, and bIndexSubType==0 gives wLongsPerEntry=2.
  1812.         // Matrox's MPEG-2 stuff generates bIndexSubType=16 and wLongsPerEntry=6.
  1813.         // *sigh*
  1814.         //
  1815.         // For wLongsPerEntry==2 and ==3, dwOffset is at 0 and dwLength at 1;
  1816.         // for wLongsPerEntry==6, dwOffset is at 2 and all are keyframes.
  1817.  
  1818.         {
  1819.             if (idxstd.wLongsPerEntry!=2 && idxstd.wLongsPerEntry!=3 && idxstd.wLongsPerEntry!=6)
  1820.                 throw MyError("Invalid OpenDML index block in stream (wLongsPerEntry=%d)", idxstd.wLongsPerEntry);
  1821.  
  1822.             while(entries > 0) {
  1823.                 tp = (sizeof dwHeap / sizeof dwHeap[0]) / idxstd.wLongsPerEntry;
  1824.                 if (tp>entries) tp=entries;
  1825.  
  1826.                 _readFile2(dwHeap, tp*idxstd.wLongsPerEntry*sizeof(DWORD));
  1827.  
  1828.                 if (idxstd.wLongsPerEntry == 6)
  1829.                     for(i=0; i<tp; i++) {
  1830.                         DWORD dwOffset = dwHeap[i*idxstd.wLongsPerEntry + 0];
  1831.                         DWORD dwSize = dwHeap[i*idxstd.wLongsPerEntry + 2];
  1832.  
  1833.                         pasn->index.add(idxstd.dwChunkId, (idxstd.qwBaseOffset+dwOffset)-8, dwSize, true);
  1834.  
  1835.                         pasn->bytes += dwSize;
  1836.                     }
  1837.                 else
  1838.                     for(i=0; i<tp; i++) {
  1839.                         DWORD dwOffset = dwHeap[i*idxstd.wLongsPerEntry + 0];
  1840.                         DWORD dwSize = dwHeap[i*idxstd.wLongsPerEntry + 1];
  1841.  
  1842.                         pasn->index.add(idxstd.dwChunkId, (idxstd.qwBaseOffset+dwOffset)-8, dwSize&0x7FFFFFFF, !(dwSize&0x80000000));
  1843.  
  1844.                         pasn->bytes += dwSize & 0x7FFFFFFF;
  1845.                     }
  1846.  
  1847.                 entries -= tp;
  1848.             }
  1849.         }
  1850.  
  1851.         break;
  1852.  
  1853.     default:
  1854.         throw MyError("Unknown hyperindex type");
  1855.     }
  1856.  
  1857.     _seekFile(i64FPSave);
  1858. }
  1859.  
  1860. void AVIReadHandler::_destruct() {
  1861.     AVIStreamNode *pasn;
  1862.     AVIFileDesc *pDesc;
  1863.  
  1864.     if (pAvisynthClipInfo)
  1865.         pAvisynthClipInfo->Release();
  1866.  
  1867.     if (paf)
  1868.         AVIFileRelease(paf);
  1869.  
  1870.     while(pasn = listStreams.RemoveTail())
  1871.         delete pasn;
  1872.  
  1873.     delete streamBuffer;
  1874.  
  1875.     if (listFiles.IsEmpty()) {
  1876.         if (hFile != INVALID_HANDLE_VALUE)
  1877.             CloseHandle(hFile);
  1878.         if (hFileUnbuffered != INVALID_HANDLE_VALUE)
  1879.             CloseHandle(hFileUnbuffered);
  1880.     } else
  1881.         while(pDesc = listFiles.RemoveTail()) {
  1882.             CloseHandle(pDesc->hFile);
  1883.             CloseHandle(pDesc->hFileUnbuffered);
  1884.             delete pDesc;
  1885.         }
  1886.  
  1887.     delete pSegmentHint;
  1888. }
  1889.  
  1890. ///////////////////////////////////////////////////////////////////////////
  1891.  
  1892. void AVIReadHandler::Release() {
  1893.     if (!--ref_count)
  1894.         delete this;
  1895. }
  1896.  
  1897. void AVIReadHandler::AddRef() {
  1898.     ++ref_count;
  1899. }
  1900.  
  1901. IAVIReadStream *AVIReadHandler::GetStream(DWORD fccType, LONG lParam) {
  1902.     if (paf) {
  1903.         PAVISTREAM pas;
  1904.         HRESULT hr;
  1905.  
  1906.         hr = AVIFileGetStream(paf, &pas, fccType, lParam);
  1907.  
  1908.         if (hr)
  1909.             return NULL;
  1910.  
  1911.         return new AVIReadTunnelStream(this, pas, pAvisynthClipInfo);
  1912.     } else {
  1913.         AVIStreamNode *pasn, *pasn_next;
  1914.         int streamno = 0;
  1915.  
  1916.         pasn = listStreams.AtHead();
  1917.  
  1918.         while(pasn_next = pasn->NextFromHead()) {
  1919.             if (pasn->hdr.fccType == fccType && !lParam--)
  1920.                 break;
  1921.  
  1922.             pasn = pasn_next;
  1923.             ++streamno;
  1924.         }
  1925.  
  1926.         if (pasn_next) {
  1927.             return new AVIReadStream(this, pasn, streamno);
  1928.         }
  1929.  
  1930.         return NULL;
  1931.     }
  1932. }
  1933.  
  1934. void AVIReadHandler::EnableFastIO(bool f) {
  1935.     fDisableFastIO = !f;
  1936. }
  1937.  
  1938. bool AVIReadHandler::isOptimizedForRealtime() {
  1939.     return nRealTime!=0;
  1940. }
  1941.  
  1942. bool AVIReadHandler::isStreaming() {
  1943.     return nActiveStreamers!=0;
  1944. }
  1945.  
  1946. bool AVIReadHandler::isIndexFabricated() {
  1947.     return fFakeIndex;
  1948. }
  1949.  
  1950. bool AVIReadHandler::getSegmentHint(const char **ppszPath) {
  1951.     if (!pSegmentHint) {
  1952.         if (ppszPath)
  1953.             *ppszPath = NULL;
  1954.  
  1955.         return false;
  1956.     }
  1957.  
  1958.     if (ppszPath)
  1959.         *ppszPath = pSegmentHint+1;
  1960.  
  1961.     return !!pSegmentHint[0];
  1962. }
  1963.  
  1964. ///////////////////////////////////////////////////////////////////////////
  1965.  
  1966. void AVIReadHandler::EnableStreaming(int stream) {
  1967.     if (!fStreamsActive) {
  1968.         if (!(streamBuffer = new char[STREAM_SIZE]))
  1969.             throw MyMemoryError();
  1970.  
  1971.         i64StreamPosition = -1;
  1972.         sbPosition = sbSize = 0;
  1973.     }
  1974.  
  1975.     fStreamsActive |= (1<<stream);
  1976.     ++nActiveStreamers;
  1977. }
  1978.  
  1979. void AVIReadHandler::DisableStreaming(int stream) {
  1980.     fStreamsActive &= ~(1<<stream);
  1981.  
  1982.     if (!fStreamsActive) {
  1983.         delete streamBuffer;
  1984.         streamBuffer = NULL;
  1985.     }
  1986.     --nActiveStreamers;
  1987. }
  1988.  
  1989. void AVIReadHandler::AdjustRealTime(bool fInc) {
  1990.     if (fInc)
  1991.         ++nRealTime;
  1992.     else
  1993.         --nRealTime;
  1994. }
  1995.  
  1996. char *AVIReadHandler::_StreamRead(long& bytes) {
  1997.     if (nCurrentFile<0 || nCurrentFile != (int)(i64StreamPosition>>48))
  1998.         _SelectFile((int)(i64StreamPosition>>48));
  1999.  
  2000.     if (sbPosition >= sbSize) {
  2001.         if (nRealTime || (((i64StreamPosition&0x0000FFFFFFFFFFFFi64)+sbSize) & -STREAM_BLOCK_SIZE)+STREAM_SIZE > i64Size) {
  2002.             i64StreamPosition += sbSize;
  2003.             sbPosition = 0;
  2004.             _seekFile(i64StreamPosition & 0x0000FFFFFFFFFFFFi64);
  2005.  
  2006.             sbSize = _readFile(streamBuffer, STREAM_RT_SIZE);
  2007.  
  2008.             if (sbSize < 0) {
  2009.                 sbSize = 0;
  2010.                 throw MyWin32Error("Failure streaming AVI file: %%s.",GetLastError());
  2011.             }
  2012.         } else {
  2013.             i64StreamPosition += sbSize;
  2014.             sbPosition = i64StreamPosition & (STREAM_BLOCK_SIZE-1);
  2015.             i64StreamPosition &= -STREAM_BLOCK_SIZE;
  2016.             _seekFileUnbuffered(i64StreamPosition & 0x0000FFFFFFFFFFFFi64);
  2017.  
  2018.             sbSize = _readFileUnbuffered(streamBuffer, STREAM_SIZE);
  2019.  
  2020.             if (sbSize < 0) {
  2021.                 sbSize = 0;
  2022.                 throw MyWin32Error("Failure streaming AVI file: %%s.",GetLastError());
  2023.             }
  2024.         }
  2025.     }
  2026.  
  2027.     if (sbPosition >= sbSize)
  2028.         return NULL;
  2029.  
  2030.     if (bytes > sbSize - sbPosition)
  2031.         bytes = sbSize - sbPosition;
  2032.  
  2033.     sbPosition += bytes;
  2034.  
  2035.     return streamBuffer + sbPosition - bytes;
  2036. }
  2037.  
  2038. bool AVIReadHandler::Stream(AVIStreamNode *pusher, __int64 pos) {
  2039.     bool read_something = false;
  2040.  
  2041.     if (!streamBuffer)
  2042.         return false;
  2043.  
  2044.     if (i64StreamPosition == -1) {
  2045.         i64StreamPosition = pos;
  2046.         sbPosition = 0;
  2047.     }
  2048.  
  2049.     if (pos < i64StreamPosition+sbPosition)
  2050.         return false;
  2051.  
  2052.     // >4Mb past current position!?
  2053.  
  2054.     if (pos > i64StreamPosition+sbPosition+4194304) {
  2055. //        OutputDebugString("Resetting streaming position!\n");
  2056.         i64StreamPosition = pos;
  2057.         sbSize = sbPosition = 0;
  2058.     }
  2059.  
  2060. /*    if (pusher->hdr.fccType == 'sdiv')
  2061.         OutputDebugString("pushed by video\n");
  2062.     else
  2063.         OutputDebugString("pushed by audio\n");*/
  2064.  
  2065.     ++pusher->stream_pushes;
  2066.     pusher->stream_push_pos = pos;
  2067.  
  2068.     while(pos >= i64StreamPosition+sbPosition) {
  2069.         long actual, left;
  2070.         char *src;
  2071.         FOURCC hdr[2];
  2072.         int stream;
  2073.  
  2074.         // read next header
  2075.  
  2076.         left = 8;
  2077.         while(left > 0) {
  2078.             actual = left;
  2079.             src = _StreamRead(actual);
  2080.  
  2081.             if (!src)
  2082.                 return read_something;
  2083.  
  2084.             memcpy((char *)hdr + (8-left), src, actual);
  2085.             left -= actual;
  2086.         }
  2087.  
  2088.         stream = StreamFromFOURCC(hdr[0]);
  2089.  
  2090.         if (isxdigit(hdr[0]&0xff) && isxdigit((hdr[0]>>8)&0xff) && stream<32 &&
  2091.             ((1L<<stream) & fStreamsActive)) {
  2092.  
  2093. //            _RPT3(0,"\tstream: reading chunk at %I64x, length %6ld, stream %ld\n", i64StreamPosition+sbPosition-8, hdr[1], stream);
  2094.  
  2095.             AVIStreamNode *pasn, *pasn_next;
  2096.             int streamno = 0;
  2097.  
  2098.             pasn = listStreams.AtHead();
  2099.  
  2100.             while(pasn_next = pasn->NextFromHead()) {
  2101.                 if (streamno == stream) {
  2102.                     long left = hdr[1] + (hdr[1]&1);
  2103.                     bool fWrite = pasn->cache->WriteBegin(i64StreamPosition + sbPosition, left);
  2104.                     char *dst;
  2105.  
  2106.                     while(left > 0) {
  2107.                         actual = left;
  2108.  
  2109.                         dst = _StreamRead(actual);
  2110.                         
  2111.                         if (!dst) {
  2112.                             if (fWrite)
  2113.                                 pasn->cache->WriteEnd();
  2114.                             return read_something;
  2115.                         }
  2116.  
  2117.                         if (fWrite)
  2118.                             pasn->cache->Write(dst, actual);
  2119.  
  2120.                         left -= actual;
  2121.                     }
  2122.  
  2123.                     if (fWrite)
  2124.                         pasn->cache->WriteEnd();
  2125.  
  2126.                     read_something = true;
  2127.  
  2128.                     break;
  2129.                 }
  2130.  
  2131.                 pasn = pasn_next;
  2132.                 ++streamno;
  2133.             }
  2134.         } else {
  2135.  
  2136.             if (hdr[0] != FOURCC_LIST && hdr[0] != FOURCC_RIFF) {
  2137.                 long actual;
  2138.  
  2139.                 // skip chunk
  2140.  
  2141.                 left = hdr[1] + (hdr[1] & 1);
  2142.  
  2143.                 while(left > 0) {
  2144.                     actual = left;
  2145.  
  2146.                     if (!_StreamRead(actual))
  2147.                         return read_something;
  2148.  
  2149.                     left -= actual;
  2150.                 }
  2151.             } else {
  2152.                 left = 4;
  2153.  
  2154.                 while(left > 0) {
  2155.                     actual = left;
  2156.  
  2157.                     if (!_StreamRead(actual))
  2158.                         return read_something;
  2159.  
  2160.                     left -= actual;
  2161.                 }
  2162.             }
  2163.  
  2164.         }
  2165.     }
  2166.  
  2167.     return true;
  2168. }
  2169.  
  2170. __int64 AVIReadHandler::getStreamPtr() {
  2171.     return i64StreamPosition + sbPosition;
  2172. }
  2173.  
  2174. void AVIReadHandler::FixCacheProblems(AVIReadStream *arse) {
  2175.     AVIStreamNode *pasn, *pasn_next;
  2176.  
  2177.     // The simplest fix is simply to disable caching on the stream that's
  2178.     // cache-missing.  However, this is a bad idea if the problem is a low-bandwidth
  2179.     // audio stream that's outrunning a high-bandwidth video stream behind it.
  2180.     // Check the streaming leader, and if the streaming leader is comparatively
  2181.     // low bandwidth and running at least 512K ahead of the cache-missing stream,
  2182.     // disable its cache.
  2183.  
  2184.     AVIStreamNode *stream_leader = NULL;
  2185.     int stream_leader_no;
  2186.     int streamno=0;
  2187.  
  2188.     pasn = listStreams.AtHead();
  2189.  
  2190.     while(pasn_next = pasn->NextFromHead()) {
  2191.         if (pasn->cache)
  2192.             if (!stream_leader || pasn->stream_pushes > stream_leader->stream_pushes) {
  2193.                 stream_leader = pasn;
  2194.                 stream_leader_no = streamno;
  2195.             }
  2196.  
  2197.         pasn = pasn_next;
  2198.         ++streamno;
  2199.     }
  2200.  
  2201.     if (stream_leader && stream_leader->stream_bytes*2 < arse->psnData->stream_bytes
  2202.         && stream_leader->stream_push_pos >= arse->psnData->stream_push_pos+524288) {
  2203. #ifdef STREAMING_DEBUG
  2204.         OutputDebugString("caching disabled on fast puny leader\n");
  2205. #endif
  2206.         delete stream_leader->cache;
  2207.         stream_leader->cache = NULL;
  2208.  
  2209.         DisableStreaming(stream_leader_no);
  2210.  
  2211.         i64StreamPosition = -1;
  2212.         sbPosition = sbSize = 0;
  2213.     } else {
  2214. #ifdef STREAMING_DEBUG
  2215.         OutputDebugString("disabling caching at request of client\n");
  2216. #endif
  2217.  
  2218.         arse->EndStreaming();
  2219.  
  2220.         if (arse->psnData == stream_leader) {
  2221.             i64StreamPosition = -1;
  2222.             sbPosition = sbSize = 0;
  2223.         }
  2224.     }
  2225.  
  2226.     // Reset cache statistics on all caches.
  2227.  
  2228.     pasn = listStreams.AtHead();
  2229.  
  2230.     while(pasn_next = pasn->NextFromHead()) {
  2231.         if (pasn->cache)
  2232.             pasn->cache->ResetStatistics();
  2233.  
  2234.         pasn = pasn_next;
  2235.     }
  2236. }
  2237.  
  2238. long AVIReadHandler::ReadData(int stream, void *buffer, __int64 position, long len) {
  2239.     if (nCurrentFile<0 || nCurrentFile != (int)(position>>48))
  2240.         _SelectFile((int)(position>>48));
  2241.  
  2242. //    _RPT3(0,"Reading from file %d, position %I64x, size %d\n", nCurrentFile, position, len);
  2243.  
  2244.     if (!_seekFile2(position & 0x0000FFFFFFFFFFFFi64))
  2245.         return -1;
  2246.     return _readFile(buffer, len);
  2247. }
  2248.  
  2249. void AVIReadHandler::_SelectFile(int file) {
  2250.     AVIFileDesc *pDesc, *pDesc_next;
  2251.  
  2252.     nCurrentFile = file;
  2253.  
  2254.     pDesc = listFiles.AtHead();
  2255.     while((pDesc_next = pDesc->NextFromHead()) && file--)
  2256.         pDesc = pDesc_next;
  2257.  
  2258.     hFile            = pDesc->hFile;
  2259.     hFileUnbuffered    = pDesc->hFileUnbuffered;
  2260.     i64Size            = pDesc->i64Size;
  2261. }
  2262.